﻿using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace Stauffware.Common.Core
{
	/// <summary>
	/// Assorted utilities for dealing with enums.
	/// </summary>
	/// <remarks>
	/// Some non-obvious facts about enums:
	/// 
	/// This sequence of casts will work only if IntegerType is the underlying type of MyEnumType:
	///			(MyEnumType) (object) (IntegerType) 0
	///	
	/// This code blows up at runtime even if IntegerType is the underlying type of MyEnumType:
	///			Convert.ChangeType(myIntValue, typeof(MyEnumType))
	///			
	/// </remarks>

	public static class EnumUtils
	{
		/// <summary>
		/// Converts a signed integer value to the corresponding value in the enum type T.
		/// </summary>
		/// <typeparam name="T">the enum type to be converted to</typeparam>
		/// <param name="i">the value to be converted</param>
		/// <returns>the converted value</returns>
		public static T IntToEnum<T> (long i) where T : struct
		{
			return (T) Convert.ChangeType(i, Enum.GetUnderlyingType(typeof(T)), null);
		}

		/// <summary>
		/// Converts an unsigned integer value to the corresponding value in the enum type T.
		/// </summary>
		/// <typeparam name="T">the enum type to be converted to</typeparam>
		/// <param name="i">the value to be converted</param>
		/// <returns>the converted value</returns>
		public static T IntToEnum<T> (ulong i) where T : struct
		{
			return (T) Convert.ChangeType(i, Enum.GetUnderlyingType(typeof(T)), null);
		}

		/// <summary>
		/// Converts an unsigned integer value to the corresponding value in the given enum type.
		/// </summary>
		/// <param name="i">the value to be converted</param>
		/// <param name="enumType">the enum type to be converted to</param>
		/// <returns>the converted value</returns>
		public static object IntToEnum (ulong i, Type enumType)
		{
			return Convert.ChangeType(i, Enum.GetUnderlyingType(enumType), null);
		}

		/// <summary>
		/// A wrapper for System.Type.GetEnumValues() that works on Silverlight.
		/// </summary>
		public static ICollection GetEnumValues (Type enumType)
		{
#if !SILVERLIGHT
			return enumType.GetEnumValues();
#else
			Require.Condition(enumType.IsEnum, enumType.FullName + " is not an enum type");

			return (
			  from field in enumType.GetFields(BindingFlags.Public | BindingFlags.Static)
			  where field.IsLiteral
			  select field.GetValue(null)
			).ToArray();
#endif
		}
	}
}
